package com.tek.ding.faceding.ui.camera;

import android.Manifest;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import com.tek.ding.faceding.R;
import com.tek.ding.faceding.base.BaseActivity;
import com.tek.ding.faceding.bean.BaseBean;
import com.tek.ding.faceding.bean.Members;
import com.tek.ding.faceding.presenter.camera.CameraContract;
import com.tek.ding.faceding.presenter.camera.CameraModel;
import com.tek.ding.faceding.presenter.camera.CameraPresenter;
import com.tek.ding.faceding.ui.book.ScanBookActivity;
import com.tek.ding.faceding.utils.BitmapUtil;
import com.tek.ding.faceding.utils.Config;
import com.tek.ding.faceding.utils.Constants;
import com.tek.ding.faceding.utils.MyToastUtils;
import com.tek.ding.faceding.utils.OssService;
import com.tek.ding.faceding.utils.PermissionUtils;
import com.tek.ding.faceding.utils.SPUtils;
import com.tek.ding.faceding.utils.loading.CircleDialog;
import com.tek.ding.faceding.utils.opengl.Renderer;
import com.tek.ding.faceding.utils.opengl.carema.FrameCallback;
import com.tek.ding.faceding.utils.opengl.carema.TextureController;
import com.tek.ding.faceding.utils.opengl.filter.ZipPkmAnimationFilter;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;

import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;

public class CameraActivity extends BaseActivity<CameraPresenter> implements CameraContract.CameraView, FrameCallback {

    private static final String CAMERA_CONTROLL = "CAMERA_CONTROLL";
    private static final String TYPE = "type";
    private static final String MEMBER_ID = "memberId";
    private static final String SHOP_MEMBER = "members";

    // 0表示后置摄像头 1表示前置摄像头
    private TextView countDownEditTextView;
    private ImageView tbImg;
    private int currentTimer = 3;

    private Context context;
    private Disposable subscribe;

    private Members members;
    private int type = 0;
    private OssService ossService = null;

    /**/
    private static final String TAG = CameraActivity.class.getSimpleName();

    private SurfaceView mSurfaceView;
    private Renderer mRenderer;
    private int cameraId = 1;

    private TextureController mController;
    private SurfaceHolder.Callback callback;

    private String storeUid;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_camera_opengl;
    }

    @Override
    protected String setTitleName() {
        type = getIntent().getIntExtra(TYPE, 0);
        if (type == 1) {
            return "人脸录入";
        } else if (type == 2) {
            return "签到";
        } else if (type == 3) {
            return "签退";
        } else if (type == 4) {
            return "人脸识别";
        } else {
            return "";
        }
    }

    @Override
    protected CameraPresenter createPresenter() {
        return new CameraPresenter(new CameraModel(), this);
    }

    @Override
    protected void init() {
        context = CameraActivity.this;
        members = getIntent().getParcelableExtra(SHOP_MEMBER);

        storeUid = SPUtils.getString(Constants.STORE_UID, "");

        tbImg = find(R.id.tbImg);
        countDownEditTextView = find(R.id.countDownEditTextView);

        countDownEditTextView.setText(String.valueOf(currentTimer));

        //人脸录入，显示切换前后置摄像头按钮，默认后置摄像头
//        if (type != 1 && type != 4) {
//            tbImg.setVisibility(View.VISIBLE);
//            RxView.clicks(tbImg)
//                    .throttleFirst(1, TimeUnit.SECONDS)
//                    .subscribe(unit -> {
//                        if (subscribe != null) {
//                            subscribe.dispose();
//                        }
//                        if (mController != null) {
//                            if (cameraId == 0) {
//                                cameraId = 1;
//                            } else {
//                                cameraId = 0;
//                            }
//                            mRenderer.onDestroy();
//                            //TODO 设置数据源
//                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//                                mRenderer = new Camera2Renderer();
//                            } else {
//                                mRenderer = new Camera1Renderer();
//                            }
//                            mController.setRenderer(mRenderer);
//                        }
//                        rxJavaInterval();
//                    });
//        }

        PermissionUtils.askPermission(this, new String[]{Manifest.permission.CAMERA, Manifest
                .permission.WRITE_EXTERNAL_STORAGE}, 10, initViewRunnable);
        //倒计时
        rxJavaInterval();

        // 设置美颜
        setMeiYan();
    }

    public void setMeiYan() {

    }

    /**
     * 倒计时拍照
     */
    private void rxJavaInterval() {
        //开始倒计时
        Observable.interval(0, 1, TimeUnit.SECONDS)//延迟0，间隔1s，单位秒
                .take(currentTimer + 1)//限制发射次数（因为倒计时要显示 3 2 1 0 四个数字）
                //使用map将数字转换，这里aLong是从0开始增长的,所以减去aLong就会输出3 2 1 0这种样式
                .map(aLong -> currentTimer - aLong)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        subscribe = d;
                    }

                    @Override
                    public void onNext(Long num) {
                        //接收到消息，这里需要判空，因为3秒倒计时中间如果页面结束了，会造成找不到 tvAdCountDown
                        countDownEditTextView.setText(String.valueOf(num));
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        //倒计时结束，开始拍照
                        countDownEditTextView.setText("");
                        if (mController != null) {
                            CircleDialog.show(context);
                            mController.takePhoto();
                        }
                    }
                });
    }

    protected void onFilterSet(TextureController controller) {
        ZipPkmAnimationFilter mAniFilter = new ZipPkmAnimationFilter(getResources());
        mAniFilter.setAnimation("assets/etczip/cc.zip");
        controller.addFilter(mAniFilter);
    }

    private Runnable initViewRunnable = new Runnable() {
        @Override
        public void run() {

            //TODO 设置数据源
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mRenderer = new Camera2Renderer();
            } else {
                mRenderer = new Camera1Renderer();
            }
            mSurfaceView = findViewById(R.id.mSurface);
            mController = new TextureController(CameraActivity.this);
            onFilterSet(mController);
            mController.setFrameCallback(720, 1280, CameraActivity.this);
            mSurfaceView.getHolder().addCallback(getSurfaceHolderCallback());

        }
    };

    private SurfaceHolder.Callback getSurfaceHolderCallback() {
        return callback = new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mController.surfaceCreated(holder);
                mController.setRenderer(mRenderer);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                mController.surfaceChanged(width, height);
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                mController.surfaceDestroyed();
            }
        };
    }


    @Override
    public void onFrame(byte[] bytes, long time) {
        new Thread(() -> {
            mController.destroy();
            Bitmap bitmap = Bitmap.createBitmap(720, 1280, Bitmap.Config.ARGB_8888);
            ByteBuffer b = ByteBuffer.wrap(bytes);
            bitmap.copyPixelsFromBuffer(b);
            saveBitmap(bitmap);
            bitmap.recycle();
        }).start();
    }

    //图片保存
    public void saveBitmap(Bitmap bitmap) {
        try {
            //保存到data/data目录自定义文件夹下
            File dirFile = new File(Config.PHOTO_PATH);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            String photoUrl = "";
            photoUrl = BitmapUtil.saveBitmap2Gallery(context, bitmap, 0);
            Log.d("ImageUtils ", photoUrl);
            //上传照片到阿里云
            loadToOss(photoUrl);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

    /**
     * 上传照片到阿里云
     */
    private void loadToOss(String photoUrl) {
        if (ossService == null) {
            //初始化OssService类，参数分别是Content，accessKeyId，accessKeySecret，endpoint，bucketName（后4个参数是您自己阿里云Oss中参数）
            ossService = new OssService(this);
            //初始化OSSClient
            ossService.initOSSClient();
        }
        if (type == 1) {
            String uploadUrl = ossService.uploadFace(Config.addFaceFileDir, photoUrl);
            presenter.addFaceEntity2(storeUid, members.getUid(), uploadUrl);
        } else if (type == 2) {
            String uploadUrl = ossService.uploadFace(Config.searchFaceFileDir, photoUrl);
            presenter.toShopFace2(storeUid, uploadUrl);
        } else if (type == 3) {
            String uploadUrl = ossService.uploadFace(Config.searchFaceFileDir, photoUrl);
            presenter.leaveShopFace2(storeUid, uploadUrl);
        } else if (type == 4) {
            String uploadUrl = ossService.uploadFace(Config.searchFaceFileDir, photoUrl);
            presenter.getMemberByFaceImg2(storeUid, uploadUrl);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        PermissionUtils.onRequestPermissionsResult(requestCode == 10, grantResults, initViewRunnable,
                () -> {
                    Toast.makeText(CameraActivity.this, "没有获得必要的权限", Toast.LENGTH_SHORT).show();
                    finish();
                });
    }

    @Override
    public void addFaceEntityOk(BaseBean<String> baseBean) {
        CircleDialog.dismiss(context);
        String msg = "";
        if (baseBean.success()) {
            msg = members.getFullName().concat("，\n人脸录入成功！");
        } else {
            msg = baseBean.getMsg();
        }
        MyToastUtils.showLong(msg);
        finish();
    }

    @Override
    public void toShopFaceOk(BaseBean<String> baseBean) {
        CircleDialog.dismiss(context);
        String msg = "";
        if (baseBean.success()) {
            msg = baseBean.getData().concat("，\n签到成功！");
        } else {
            msg = baseBean.getMsg();
        }
        MyToastUtils.showLong(msg);
        finish();
    }

    @Override
    public void leaveShopFaceOk(BaseBean<String> baseBean) {
        CircleDialog.dismiss(context);
        String msg = "";
        if (baseBean.success()) {
            msg = baseBean.getData().concat("，\n签退成功！");
        } else {
            msg = baseBean.getMsg();
        }
        MyToastUtils.showLong(msg);
        finish();
    }

    @Override
    public void getMemberByFaceImgOk(BaseBean<Members> baseBean) {
        CircleDialog.dismiss(context);
        String msg = "";
        if (baseBean.success()) {
            if (baseBean.getData() != null) {
                //获取会员信息成功，去扫条形码
                ScanBookActivity.startActivity(context, baseBean.getData());
            } else {
                msg = "会员未查询到！";
                MyToastUtils.showLong(msg);
            }
        } else {
            msg = baseBean.getMsg();
            MyToastUtils.showLong(msg);
        }
        finish();
    }

    @Override
    public void showError(String msg) {
        CircleDialog.dismiss(context);
        super.showError(msg);
        finish();
    }

    /**
     * Camera
     */
    private class Camera1Renderer implements Renderer {

        private Camera mCamera;

        @Override
        public void onDestroy() {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        }

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
            mCamera = Camera.open(cameraId);
            mController.setImageDirection(cameraId);
            Camera.Size size = mCamera.getParameters().getPreviewSize();
            mController.setDataSize(size.height, size.width);
            try {
                mCamera.setPreviewTexture(mController.getTexture());
                mController.getTexture().setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
                    @Override
                    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                        mController.requestRender();
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
            mCamera.startPreview();
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {

        }

        @Override
        public void onDrawFrame(GL10 gl) {

        }
    }

    /**
     * Camera2
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private class Camera2Renderer implements Renderer {

        CameraDevice mCamera2;
        CameraManager mCameraManager;
        private HandlerThread mThread;
        private Handler mHandler;
        private Size mPreviewSize;

        Camera2Renderer() {
            mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
            mThread = new HandlerThread("camera2 ");
            mThread.start();
            mHandler = new Handler(mThread.getLooper());
        }

        @Override
        public void onDestroy() {
            if (mCamera2 != null) {
                mCamera2.close();
                mCamera2 = null;
            }
        }

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            try {
                if (mCamera2 != null) {
                    mCamera2.close();
                    mCamera2 = null;
                }
                CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId + "");
                StreamConfigurationMap map = c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                Size[] sizes = map.getOutputSizes(SurfaceHolder.class);
                //自定义规则，选个大小
                mPreviewSize = sizes[0];
                mController.setDataSize(mPreviewSize.getHeight(), mPreviewSize.getWidth());
                mCameraManager.openCamera(cameraId + "", new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(CameraDevice camera) {
                        mCamera2 = camera;
                        try {
                            Surface surface = new Surface(mController.getTexture());
                            final CaptureRequest.Builder builder = mCamera2.createCaptureRequest(TEMPLATE_PREVIEW);
                            builder.addTarget(surface);
                            mController.getTexture().setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
                            mCamera2.createCaptureSession(Arrays.asList(surface), new
                                    CameraCaptureSession.StateCallback() {
                                        @Override
                                        public void onConfigured(CameraCaptureSession session) {
                                            try {
                                                session.setRepeatingRequest(builder.build(), new CameraCaptureSession.CaptureCallback() {
                                                    @Override
                                                    public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
                                                        super.onCaptureProgressed(session, request, partialResult);
                                                    }

                                                    @Override
                                                    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                                                        super.onCaptureCompleted(session, request, result);
                                                        mController.requestRender();
                                                    }
                                                }, mHandler);
                                            } catch (CameraAccessException e) {
                                                e.printStackTrace();
                                            }
                                        }

                                        @Override
                                        public void onConfigureFailed(CameraCaptureSession session) {

                                        }
                                    }, mHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onDisconnected(CameraDevice camera) {
                        mCamera2 = null;
                    }

                    @Override
                    public void onError(CameraDevice camera, int error) {

                    }
                }, mHandler);
            } catch (SecurityException | CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {

        }

        @Override
        public void onDrawFrame(GL10 gl) {

        }
    }


    @Override
    protected void onResume() {
        super.onResume();
        if (mController != null) {
            mController.onResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mController != null) {
            mController.onPause();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mController != null) {
            mController.destroy();
        }
        if (subscribe != null) {
            subscribe.dispose();
            subscribe = null;
        }
    }

}
